﻿#ifndef Dir_h__2013_7_30__10_32
#define Dir_h__2013_7_30__10_32

#include "df.h"

namespace df
{
	struct DiskInfo
	{
		TCHAR name_[4];
		//typeInfo的索引
		int type_;
		long long totalSize_;
		long long freeSize_;


		//内联优化失败
		static CC * GetTypeInfo()
		{
			static CC typeInfo[] = {
				tcc_("[未知磁盘]"),//0
				tcc_("[无根磁盘]"),//1
				tcc_("[移动磁盘]"),//2
				tcc_("[本地磁盘]"),//3
				tcc_("[远程磁盘]"),//4
				tcc_("[光驱盘]"),  //5
				tcc_("[内存盘]"),  //6
			};
			return typeInfo;
		}


#ifdef WIN32
		static_assert(DRIVE_UNKNOWN == 0 && DRIVE_RAMDISK == 6, "typeInfo error");
#endif
	};

#ifdef WIN32
	struct FileAttribute
	{
		enum{
			DIRECTORY = FILE_ATTRIBUTE_DIRECTORY,
			HIDDEN = FILE_ATTRIBUTE_HIDDEN,
			READONLY = FILE_ATTRIBUTE_READONLY,
			SYSTEM = FILE_ATTRIBUTE_SYSTEM,
			ARCHIVE = FILE_ATTRIBUTE_ARCHIVE,
			DEVICE = FILE_ATTRIBUTE_DEVICE,
			NORMAL = FILE_ATTRIBUTE_NORMAL,
			TEMPORARY = FILE_ATTRIBUTE_TEMPORARY,
		};
	};
#else
	struct FileAttribute
	{
		enum{
			DIRECTORY = df::Binary<unsigned,1>::value,
			HIDDEN    = df::Binary<unsigned,10>::value,
			READONLY  = df::Binary<unsigned,100>::value,
			SYSTEM    = df::Binary<unsigned,1000>::value,
			ARCHIVE   = df::Binary<unsigned,10000>::value,
			DEVICE    = df::Binary<unsigned,100000>::value,
			NORMAL	  = df::Binary<unsigned,1000000>::value,
			TEMPORARY = df::Binary<unsigned,10000000>::value,
		};
	};
#endif

	struct FileInfo
	{

		TCHAR * name_;
		unsigned long attributes_;
		long long size_;

		inline bool IsDir() const
		{
			return (attributes_ & FileAttribute::DIRECTORY) != 0;
		}

		inline bool IsHide() const
		{
			return (attributes_ & FileAttribute::HIDDEN) != 0;
		}

		inline CC getName()
		{
			return name_;
		}

		inline bool IsFile() const
		{
			return !IsDir();
		}



	};


}

namespace df
{

	class DirRes
	{
	public:
		inline DirRes(const df::CC & menu, const df::CC & filter);


#ifdef WIN32
		inline DirRes(DirRes && r)
			:menu(r.menu)
			, has_(r.has_)
			, memBuf(r.memBuf)
			, hSearch(r.hSearch)
			, buf(r.buf)
		{
			r.memBuf = nullptr;
			r.hSearch = 0;
		}

		inline ~DirRes(){
			delete memBuf;
			FindClose(hSearch);
		}
#else
		inline DirRes(DirRes && r)
			: menu(r.menu)
			, has_(r.has_)
			, dp(r.dp)
			, entry(r.entry)
		{
			r.dp = 0;
			r.entry = 0;
		}

		inline ~DirRes()
		{
			if(dp!=0)
				closedir(dp);
		}
#endif // WIN32

		class DirIter
		{
		public:
			inline DirIter(DirRes & r)
				:dirRes(r)

			{
			}

			//查找下一个文件
			inline DirIter & operator++()
			{
#ifdef WIN32
				dirRes.has_ = FindNextFile(dirRes.hSearch, dirRes.buf) != 0;
#endif
				return *this;
			}

			inline FileInfo & operator*()
			{
#ifdef WIN32
				dirRes.fInfo.name_ = dirRes.buf->cFileName;
				dirRes.fInfo.size_ = ((long long)dirRes.buf->nFileSizeHigh << sizeof(DWORD)) + dirRes.buf->nFileSizeLow;
				dirRes.fInfo.attributes_ = dirRes.buf->dwFileAttributes;
#else
				dirRes.fInfo.name_ = dirRes.entry->d_name;
				//fInfo.size_ = statbuf.st_size;
				dirRes.fInfo.size_ = 0;
				dirRes.fInfo.attributes_ = 0;

				if (dirRes.entry->d_type & DT_DIR)
					dirRes.fInfo.attributes_ |= df::FileAttribute::DIRECTORY;

				if (dirRes.entry->d_name[0] == _T('.')){
					dirRes.fInfo.attributes_ |= df::FileAttribute::HIDDEN;
				}
#endif
				return dirRes.fInfo;
			}

			inline bool operator !=(DirIter)
			{
#ifdef WIN32
				///排除.和..文件
				while (dirRes.has_
					&& dirRes.buf->cFileName[0] == _T('.')
					&& (dirRes.buf->cFileName[1] == 0 || dirRes.buf->cFileName[2] == 0)){
					operator++();
				}
#else
				while(dirRes.has_) {

					dirRes.has_ = (dirRes.entry = readdir(dirRes.dp)) != NULL;

					if(!dirRes.has_)
						break;
					//lstat(entry->d_name, &statbuf);

					///排除.和..文件
					if (dirRes.entry->d_name[0] == _T('.') && (dirRes.entry->d_name[1] == 0 || dirRes.entry->d_name[2] == 0))
						continue;

					break;
				}
#endif

				return dirRes.has_;
			}

		private:
			DirRes & dirRes;
		};


		inline DirIter begin()
		{
			return DirIter(*this);
		}

		inline DirIter end()
		{
			return DirIter(*this);
		}

	private:

		df::CC menu;
		bool has_;
		df::FileInfo fInfo;

#ifdef WIN32
		char * memBuf;
		HANDLE hSearch;
		WIN32_FIND_DATA * buf;
#else
		DIR *dp;
		struct dirent *entry;
#endif

		DF_DISABLE_COPY_ASSIGN(DirRes);
	};


	//*******************************************
	// Summary : 遍历文件夹(不包括子文件夹)
	// Parameter - const df::CC & menu : 文件夹
	// Parameter - const df::CC filter : 通配符,过滤器
	// Returns - DirRes : 结果
	//*******************************************
	inline DirRes EachDir(const df::CC & menu, const df::CC & filter = _T("*.*")){
		return DirRes(menu, filter);
	}

	//遍历磁盘,回调:df::DiskInfo
	//返回磁盘个数
	template<class LamT>
	int EachDisk(LamT lam);


	inline String & getCurrentDirString(){
		static String menu;
		return menu;
	}

	//获取本进程目录
	inline df::CC GetDirCurrent();


	//获取本进程目录(包括exe名)
	inline String GetDirExe()
	{
		String menu(MAX_PATH, 0);
#ifdef WIN32
		///获取模块路径
		DWORD menuLen = ::GetModuleFileName(0, &menu[0],(DWORD)menu.capacity());
		if (menuLen != 0)
			menu.resize(menuLen);
#endif // WIN32
		return menu;
	}


}



#endif // Dir_h__2013_7_30__10_32
